package com.evil.application.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.account.api.RemoteUserEnterpriseService;
import com.evil.application.api.RemoteApplicationPackageService;
import com.evil.application.mapper.ApplicationPackageMapper;
import com.evil.application.pojo.dto.AppTreeDTO;
import com.evil.application.pojo.dto.ApplicationReqDTO;
import com.evil.application.pojo.dto.ItemDTO;
import com.evil.application.pojo.dto.ReorderApplicationReqDTO;
import com.evil.application.pojo.dto.pack.*;
import com.evil.application.pojo.entity.ApplicationPackage;
import com.evil.application.pojo.entity.PackageApplication;
import com.evil.application.service.*;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.application.dto.permission.app.AppPermissionDTO;
import com.evil.common.application.dto.permission.app.AppPermissionSourceDTO;
import com.evil.common.application.dto.permission.app.AppPermissionsListDTO;
import com.evil.common.application.dto.permission.app.ModifyAppPermissionReqDTO;
import com.evil.common.application.dto.pkg.PackageApplicationSourceDTO;
import com.evil.common.application.enums.ApplicationSourceTypeEnum;
import com.evil.common.application.enums.permission.PermissionStatusEnum;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.file.dto.FileRespDTO;
import com.evil.file.api.RemoteFileService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 应用包表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@AllArgsConstructor
public class ApplicationPackageServiceImpl extends ServiceImpl<ApplicationPackageMapper, ApplicationPackage> implements ApplicationPackageService, RemoteApplicationPackageService {

    private final LoginUtil loginUtil;

    private final PackageApplicationService packageApplicationService;

    private final ApplicationGroupService applicationGroupService;

    private final ApplicationInfoService applicationInfoService;

    private final ApplicationPermissionService applicationPermissionService;

    private final RemoteUserEnterpriseService userEnterpriseService;

    private final RemoteFileService remoteFileService;

    private final ApplicationLogServiceImpl applicationLogService;

    /**
     * 获取应用包基础信息
     *
     * @param packageId 应用包id
     * @return PackageBaseInfoRespDTO
     */
    @Override
    public PackageBaseInfoRespDTO packageBaseInfo(Long packageId) {
        ApplicationPackage applicationPackage = this.baseMapper.findById(packageId);
        // 检查企业
        loginUtil.checkEnterpriseId(applicationPackage.getEnterpriseId());

        // 获取应用包权限
        List<AppPermissionDTO> permissions = applicationPermissionService.findDTOBySource(
                new AppPermissionSourceDTO(ApplicationSourceTypeEnum.PACKAGE.getId(), packageId));

        PackageBaseInfoRespDTO baseInfoRespDTO = new PackageBaseInfoRespDTO(applicationPackage);
        baseInfoRespDTO.setPermissions(permissions);

        return baseInfoRespDTO;
    }

    /**
     * 获取应用包信息
     *
     * @param packageAppListInfoReqDTO packageAppListInfoReqDTO
     * @return PackageBaseInfoRespDTO
     */
    @Override
    public PackageInfoRespDTO packageInfo(PackageAppListInfoReqDTO packageAppListInfoReqDTO) {
        Long packageId = packageAppListInfoReqDTO.getPackageId();
        ApplicationPackage applicationPackage = this.baseMapper.findById(packageId);
        // 检查企业
        loginUtil.checkEnterpriseId(applicationPackage.getEnterpriseId());

        ApplicationReqDTO applicationReqDTO = new ApplicationReqDTO();
        applicationReqDTO.setPackageId(packageId);
        List<AppTreeDTO> applicationTree = applicationInfoService.applicationTree(applicationReqDTO);

        // 检查是否是管理员
        boolean enterpriseManager = userEnterpriseService.enterpriseManager(loginUtil.getLoginUserEnterprise());

        PackageInfoRespDTO packageInfoRespDTO = new PackageInfoRespDTO();
        packageInfoRespDTO.setCanAdd(enterpriseManager);
        packageInfoRespDTO.setCanModify(enterpriseManager);
        packageInfoRespDTO.setCanDelete(enterpriseManager);
        packageInfoRespDTO.setCanReorder(enterpriseManager);
        packageInfoRespDTO.setPackageName(applicationPackage.getPackageName());
        packageInfoRespDTO.setItems(applicationTree.stream().map(e -> (ItemDTO) e).collect(Collectors.toList()));
        return packageInfoRespDTO;
    }

    /**
     * 获取应用包列表
     *
     * @param packageListReqDTO packageListReqDTO
     * @return PackageRespDTO 列表
     */
    @Override
    public List<PackageRespDTO> packageList(PackageListReqDTO packageListReqDTO) {
        Long enterpriseId = loginUtil.getParamEnterpriseId(packageListReqDTO.getEnterpriseId());
        return this.baseMapper.findByEnterpriseId(enterpriseId).stream()
                .filter(e -> applicationPermissionService.loginUserHasPermission(
                        e.getEnterpriseId(),
                        e.getPermissionStatus(),
                        new AppPermissionSourceDTO(ApplicationSourceTypeEnum.PACKAGE, e.getPackageId()),
                        false))
                .map(PackageRespDTO::new)
                .collect(Collectors.toList());
    }

    /**
     * 新增应用包
     *
     * @param addPackageReqDTO addPackageReqDTO
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void addPackage(AddPackageReqDTO addPackageReqDTO) {
        Long enterpriseId = loginUtil.getParamEnterpriseId(addPackageReqDTO.getEnterpriseId());
        // 检查是否是管理员
        userEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        // 获取该企业应用包最大序号
        int maxSort = this.baseMapper.findMaxSortByEnterpriseId(enterpriseId);

        ApplicationPackage applicationPackage = new ApplicationPackage();
        applicationPackage.setEnterpriseId(enterpriseId);
        applicationPackage.setPackageName(addPackageReqDTO.getPackageName());
        // icon
        if (StringUtils.isNotBlank(addPackageReqDTO.getIconFileCode())) {
            FileRespDTO iconFileBase = remoteFileService.findBaseByFileCode(addPackageReqDTO.getIconFileCode());
            applicationPackage.setIcon(iconFileBase.getFileId());
        }
        applicationPackage.setPermissionStatus(addPackageReqDTO.getPermissionStatus());
        applicationPackage.setSort(maxSort + 1);

        applicationLogService.saveAndCheck(this.baseMapper, ApplicationPackage::getPackageId, applicationPackage);

        // 编辑应用包应用权限
        this.saveApplicationPermission(applicationPackage, addPackageReqDTO);
    }

    /**
     * 重新排序应用包
     *
     * @param packageIds packageIds
     */
    @Override
    public void reorderPackage(List<Long> packageIds) {
        // 检查是否是管理员
        userEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        List<ApplicationPackage> packageList = this.baseMapper.findByIds(packageIds, true);
        if (packageList.size() != packageIds.size()) {
            throw new BusinessException(RCodeEnum.APPLICATION_PACKAGE_NOT_EXIST);
        }
        // 拒绝访问
        packageList.forEach(e -> loginUtil.checkEnterpriseId(e.getEnterpriseId()));

        Map<Long, ApplicationPackage> packageMap = packageList.stream().collect(Collectors.toMap(ApplicationPackage::getPackageId, e -> e));

        AtomicInteger i = new AtomicInteger(1);
        List<ApplicationPackage> packages = packageIds.stream()
                .filter(packageMap::containsKey)
                .map(packageMap::get)
                .peek(e -> e.setSort(i.getAndIncrement()))
                .collect(Collectors.toList());

        applicationLogService.saveAndCheck(this.baseMapper, ApplicationPackage::getPackageId, packages);
    }

    /**
     * 编辑应用包
     *
     * @param modifyPackageReqDTO modifyPackageReqDTO
     */
    @Override
    public void modifyPackage(ModifyPackageReqDTO modifyPackageReqDTO) {
        // 检查是否是管理员
        userEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        ApplicationPackage applicationPackage = this.baseMapper.findById(modifyPackageReqDTO.getPackageId());
        // 检查企业
        loginUtil.checkEnterpriseId(applicationPackage.getEnterpriseId());

        applicationPackage.setPackageName(modifyPackageReqDTO.getPackageName());
        applicationPackage.setPermissionStatus(modifyPackageReqDTO.getPermissionStatus());

        applicationLogService.saveAndCheck(this.baseMapper, ApplicationPackage::getPackageId, applicationPackage);

        // 编辑应用包应用权限
        this.saveApplicationPermission(applicationPackage, modifyPackageReqDTO);
    }

    /**
     * 删除应用包
     *
     * @param deletePackageReqDTO deletePackageReqDTO
     */
    @Override
    public void deletePackage(DeletePackageReqDTO deletePackageReqDTO) {
        ApplicationPackage applicationPackage = this.baseMapper.findById(deletePackageReqDTO.getPackageId());

        // 检查是否是管理员
        userEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        // 检查企业
        loginUtil.checkEnterpriseId(applicationPackage.getEnterpriseId());

        applicationPackage.setIsDeleted(SwitchEnum.YES.getId());
        applicationLogService.saveAndCheck(this.baseMapper, ApplicationPackage::getPackageId, applicationPackage);

        List<PackageApplication> packageApplications = packageApplicationService.deletePackageApplication(new PackageApplicationSourceDTO(
                ApplicationSourceTypeEnum.PACKAGE, applicationPackage.getPackageId()));

        // 同步删除包内应用组和应用和应用数据
        if (deletePackageReqDTO.isSyncDeleteApp()) {
            packageApplications.forEach(e -> {
                if (ApplicationSourceTypeEnum.GROUP.getId() == e.getSourceType()) {
                    applicationGroupService.deleteGroup(e.getSourceId());
                }
                if (ApplicationSourceTypeEnum.APPLICATION.getId() == e.getSourceType()) {
                    applicationInfoService.deleteById(e.getSourceId());
                }
            });
        }
    }

    /**
     * 重新排序应用包应用
     *
     * @param reorderApplicationReqDTO reorderApplicationReqDTO
     */
    @Override
    public void reorderApplication(ReorderApplicationReqDTO reorderApplicationReqDTO) {
        // 检查是否是管理员
        userEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        // 获取应用包
        this.baseMapper.findById(reorderApplicationReqDTO.getPackageId());

        // 保存排序
        packageApplicationService.reorderApplication(reorderApplicationReqDTO);
    }

    /**
     * 编辑应用包 指定 应用权限
     *
     * @param applicationPackage    applicationPackage
     * @param appPermissionsListDTO appPermissionsListDTO
     */
    private void saveApplicationPermission(ApplicationPackage applicationPackage, AppPermissionsListDTO appPermissionsListDTO) {
        if (PermissionStatusEnum.ASSIGN.getId() == appPermissionsListDTO.getPermissionStatus()) {
            ModifyAppPermissionReqDTO modifyAppPermissionReqDTO = new ModifyAppPermissionReqDTO();
            modifyAppPermissionReqDTO.setEnterpriseId(applicationPackage.getEnterpriseId());
            modifyAppPermissionReqDTO.setSourceType(ApplicationSourceTypeEnum.PACKAGE.getId());
            modifyAppPermissionReqDTO.setSourceId(applicationPackage.getPackageId());
            modifyAppPermissionReqDTO.setPermissions(appPermissionsListDTO.getPermissions());
            applicationPermissionService.modifyPermission(modifyAppPermissionReqDTO);
        }
    }
}
